package util;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import modelo.Condicion;
import modelo.ResultadoCondicion;
import modelo.Situacion;
import modelo.Teoria;

public class ManagerTeoria {
	
	public static void generalizar(Situacion s, Map<String, String> mapaEquivalencia){
		for (Iterator i = s.getEstado().iterator(); i.hasNext(); ){
			Condicion c = (Condicion) i.next();			
			c.setVariableA(mapaEquivalencia.get(c.getVariableA()));
			c.setVariableB(mapaEquivalencia.get(c.getVariableB()));			
		}
	}
	
	public static Teoria aplicarRetraccion(Teoria t, Situacion s){
		Teoria tm = new Teoria("Tm"); //Teoria mutante a generar a partir de la teoria y situacion usando retraccion
		tm.setSupuestos(t.getSupuestos()); // Los supuestos son los mismo que la teoria original
		tm.setAccion(t.getAccion()); // La accion es la misma que la teoria original
		
		ResultadoCondicion r = satisfaceCondiciones(t.getPredicciones(), s);
		
		if (!r.getSatisfaceCondiciones()){
			// Generar las condiciones predichas como la generalizacion simple entre el esperado de t y la situacion s
			Situacion sRet = new Situacion("ETm");
			sRet.setEstado((ArrayList) r.getCondicionesCumplidas()); // Se sacan las condiciones fallidas 
			tm.setPredicciones(sRet);
			
		} else {
			// Si la teoria satisface las condiciones supuestas no hay necesidad de generar la teoria mutante diferente a la original
			// Se devuelve una teoria mutante igual a la original
			tm.setPredicciones(t.getPredicciones());		
		}		
		
		return tm;		
	}
	
	public static ResultadoCondicion satisfaceCondiciones(Situacion supuesto, Situacion observado){
		ResultadoCondicion r = new ResultadoCondicion();
		List<Condicion> condSup = new ArrayList<Condicion>();
		condSup.addAll(supuesto.getEstado());
		List<Condicion> condObs = new ArrayList<Condicion>();
		condObs.addAll(observado.getEstado());		
		
		for (Iterator<Condicion> isup = condSup.iterator(); isup.hasNext(); ){
			Condicion csup = isup.next();
			
			for (Iterator<Condicion> iobs = condObs.iterator(); iobs.hasNext(); ){
				Condicion cobs = iobs.next();
				if (csup.getNombre().equals(cobs.getNombre())){
					if (csup.getVariableA().equals(cobs.getVariableA())){
						if (csup.getVariableB() == null && cobs.getVariableB() == null){
							r.getCondicionesCumplidas().add(cobs);
							iobs.remove();
							isup.remove();
							break;
						} else if (csup.getVariableB() != null && cobs.getVariableB() != null){
							if (csup.getVariableB().equals(cobs.getVariableB())){
								r.getCondicionesCumplidas().add(cobs);
								iobs.remove();
								isup.remove();
								break;
							}
 							
						}
					}
					
				}
				
			}
			
			if (condObs.isEmpty()){
				break;
			}			
		}
		
		r.getCondicionesFallidas().addAll(condObs);
		r.getCondicionesFallidas().addAll(condSup);
		r.setSatisfaceCondiciones(condObs.isEmpty() && condSup.isEmpty());		
		
		return r;
	}
	
	public static Map<String, String> generalizar(Teoria t) {
		Map<String, String> mapaEquivalencia = new HashMap<String, String>();
		String[] nombres = { "alfa", "beta", "chi", "delta", "epsilon" };

		/*
		 * Dado que bloque y base son los que definen una nueva variable solo
		 * agrego esas al mapa se limita a 5 variables pero cubre el alcance del
		 * libro obligatoriamente el formato de entrada de las condiciones
		 * serian un par de 'bloque' (como maximo 5 bloques puede haber) y
		 * finalmente una 'base'
		 */
		//mapaEquivalencia.clear();

		// Situacion[] sits = { t.getPredicciones(), t.getSupuestos() };
		/* Generalizo predicciones */
		Situacion sit_pred = t.getPredicciones();

		//System.out.println("Generalizando Prediccion Teoria:" + sit_pred.getNombre());
		//System.out.println("Condt o supuestos antes de generalizar:" + sit_pred.getEstado().toString());

		List<Condicion> condiciones = sit_pred.getEstado();

		Iterator ite_pred = sit_pred.getEstado().iterator();

		Boolean mapeo = true;
		Condicion c = null;
		int j = 0;
		while (ite_pred.hasNext() && mapeo) {

			c = (Condicion) ite_pred.next();
			mapaEquivalencia.put(c.getVariableA(), nombres[j]);
			/* como estoy cargando bloques c.variableB=null */

			c.setVariableA(nombres[j]);

			if (c.getNombre().equals("base")) {
				mapaEquivalencia.put(nombres[j], c.getVariableA());
				/* como estoy cargando la base c.variableB=null */

				c.setVariableA(nombres[j]);
				mapeo = false;
			}

			j++;
		}
		//System.out.println("Mapeo=" + mapaEquivalencia.toString());

		/* terminado el mapeo, continuo generalizando el resto usando el mapa */
		while (ite_pred.hasNext()) {
			c = (Condicion) ite_pred.next();
			c.setVariableA(mapaEquivalencia.get(c.getVariableA()));
			c.setVariableB(mapaEquivalencia.get(c.getVariableB()));

		}

		//System.out.println("sit gene=" + sit_pred.toString());

		/* Generalizo supuestos */
		mapaEquivalencia.clear();
		Situacion sit_supo = t.getSupuestos();

		//System.out.println("Generalizando Prediccion Teoria:" + sit_supo.getNombre());
		//System.out.println("Condt o supuestos antes de generalizar:" + sit_supo.getEstado().toString());

		List<Condicion> cond = sit_supo.getEstado();

		Iterator ite_sup = sit_supo.getEstado().iterator();

		mapeo = true;
		c = null;
		j = 0;
		while (ite_sup.hasNext() && mapeo) {

			c = (Condicion) ite_sup.next();
			mapaEquivalencia.put(c.getVariableA(), nombres[j]);
			/* como estoy cargando bloques c.variableB=null */

			c.setVariableA(nombres[j]);

			if (c.getNombre().equals("base")) {
				mapaEquivalencia.put(nombres[j], c.getVariableA());
				/* como estoy cargando la base c.variableB=null */

				c.setVariableA(nombres[j]);
				mapeo = false;
			}

			j++;
		}
		// System.out.println("Mapeo="+mapaEquivalencia.toString());
		/* terminado el mapeo, continuo generalizando el resto usando el mapa */
		while (ite_sup.hasNext()) {
			c = (Condicion) ite_sup.next();
			c.setVariableA(mapaEquivalencia.get(c.getVariableA()));
			c.setVariableB(mapaEquivalencia.get(c.getVariableB()));

		}

		//System.out.println("sit gene=" + sit_supo.toString());

		/*
		 * Generalizo la accion teniendo en cuenta el mapa cargado con el mapeo
		 * de los supuestos
		 */
		t.getAccion().setVariableA(mapaEquivalencia.get(t.getAccion().getVariableA()));
		
		return mapaEquivalencia;
	}
public static Situacion generalizarSituacion(Situacion situacion){
	Map<String, String> mapaEquivalencia = new HashMap<String, String>();
		String[] nombres = { "alfa", "beta", "chi", "delta", "epsilon" };
 
             

		System.out.println("Generalizando Prediccion Teoria:" + situacion.getNombre());
		//System.out.println("Condt o supuestos antes de generalizar:" + situacion.getEstado().toString());

		List<Condicion> condiciones = situacion.getEstado();

		Iterator ite = situacion.getEstado().iterator();

		Boolean mapeo = true;
		Condicion c = null;
		int j = 0;
		while (ite.hasNext() && mapeo) {

			c = (Condicion) ite.next();
			mapaEquivalencia.put(c.getVariableA(), nombres[j]);
			/* como estoy cargando bloques c.variableB=null */

			c.setVariableA(nombres[j]);

			if (c.getNombre().equals("base")) {
				mapaEquivalencia.put(nombres[j], c.getVariableA());
				/* como estoy cargando la base c.variableB=null */

				c.setVariableA(nombres[j]);
				mapeo = false;
			}

			j++;
		}
		System.out.println("Mapeo=" + mapaEquivalencia.toString());

		/* terminado el mapeo, continuo generalizando el resto usando el mapa */
		while (ite.hasNext()) {
			c = (Condicion) ite.next();
			c.setVariableA(mapaEquivalencia.get(c.getVariableA()));
			c.setVariableB(mapaEquivalencia.get(c.getVariableB()));

		}

		System.out.println("situacion generalizada=" + situacion.toString());

return situacion;

}
/**/
public static int teoriasimilar(Teoria t1, Teoria t2){
/*En principio mi fijo q los supuestos sean iguales*/
      ManagerTeoria.generalizar(t1);
      ManagerTeoria.generalizar(t2);
      
     ResultadoCondicion rcon= ManagerTeoria.satisfaceCondiciones(t1.getSupuestos(), t2.getSupuestos());
     if( rcon.getSatisfaceCondiciones() == true){
     /*Ahora me fijo si el conj de pred de una incluye a la otra*/
        if( t1.getPredicciones().getEstado().size() > t2.getPredicciones().getEstado().size()){
           //t1 incluye a t1
            
            
        }
     
     
     }
    
return 0;
}
/*0= la teoria no aplica para esa situacion, 1 si aplica*/
	public static int  teoriaAplicableSituacion(Teoria t, Situacion s) {
            /*Averiguo si la t esta generalizada */
            
           ManagerTeoria.generalizar(t);
           Situacion sit= ManagerTeoria.generalizarSituacion(s);
	   Situacion supuestos = t.getSupuestos();
           List<Condicion> cond_sup = new ArrayList<Condicion>();
           /*Primero pregunto si tienen el mismo tamanio*/
           if(sit.getEstado().size()!=supuestos.getEstado().size()) return 0;
           
           Iterator ite_sit=sit.getEstado().iterator();
          
           Boolean encontro=false;
           while(ite_sit.hasNext()){
           Condicion c_sit=(Condicion) ite_sit.next();
           
           /*En el bucle de abajo deberia estar*/
            Iterator ite_sup=supuestos.getEstado().iterator();
            while(ite_sup.hasNext()&&!encontro){
           
            Condicion c_sup=(Condicion) ite_sup.next();
              if(c_sit.getNombre().equals(c_sup.getNombre())){ 
                    if(c_sit.getVariableA().equals(c_sup.getVariableA())){
                            if(c_sit.getVariableB()==null && c_sup.getVariableB()==null) encontro=true;
                            if(!encontro&&c_sit.getVariableB()!=null && c_sup.getVariableB()!=null){
                                      if(c_sit.getVariableB().equals(c_sup.getVariableB()))  encontro=true;
                            } 
                           
                        
                   }
           }
           }

           }
           /*Ahora comparo la sit con los supuestos de la teoria*/
            if(!encontro) return 0;
            
		return 1;
	}
}
